package com.gbas.comu.util;

import org.apache.log4j.Logger;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import java.util.Map;

public final class EMF {
    private static final Logger logger = Logger.getLogger(EMF.class);
    private static final String defaultNameFactory = "comuFactory";
    private static String nameFactory = null;
    private static EntityManagerFactory emfInstance = null;

    private static EntityManagerFactory init() {
        return init(defaultNameFactory);
    }

     private static EntityManagerFactory init(Map properties) {
        return init(defaultNameFactory,properties);
    }
    public static EntityManagerFactory init(String newName) {
        nameFactory = newName;
        emfInstance = Persistence.createEntityManagerFactory(newName);
        logger.info("EMF inicializado a " + nameFactory);
        return emfInstance;
    }

    public static EntityManagerFactory init(String newName, Map properties) {
        nameFactory = newName;
        emfInstance = Persistence.createEntityManagerFactory(newName,properties);
        logger.info("EMF inicializado a " + nameFactory);
        return emfInstance;
    }

    public static EntityManagerFactory get() {
        if (emfInstance == null) {
            init();
        }
        return emfInstance;
    }

    public static EntityManagerFactory get(Map properties) {
        if (emfInstance == null) {
            init(properties);
        }
        return emfInstance;
    }

    public static <T> T runTransaction(final EMSession<T> ems) throws EMException {
        EntityManager em = EMF.get().createEntityManager();

        try {
            em.getTransaction().begin();
            T obj = ems.transaction();
            em.getTransaction().commit();
            return obj;
        } catch (Exception e) {
            logger.error("Realizando JPA-transaccion.", e);
            em.getTransaction().rollback();
            throw new EMException(e);
        } finally {
            em.close();
        }
    }

    public static <T> T runTransaction(EntityManager em, final EMSession<T> ems) throws EMException {
        try {
            em.getTransaction().begin();
            T obj = ems.transaction();
            em.getTransaction().commit();
            return obj;
        } catch (Exception e) {
            logger.error("Realizando JPA-transaccion.", e);
            em.getTransaction().rollback();
            throw new EMException(e);
        } catch (Throwable e) {
            logger.error("Throwable... descontrolado", e);
            em.getTransaction().rollback();
            throw new EMException(new Exception(e));
        }
    }

    public interface EMSession<T> {
        public T transaction();
    }

    public static class EMException extends RuntimeException {
        public EMException(Exception e) {
            super(e);
        }
    }

}
